package com.heo.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import com.heo.coder.packet.CommPacketRsp;
import com.heo.coder.packet.InitPacketRsp;
import com.heo.coder.packet.SetIpPortPacketRsp;
import com.heo.coder.packet.SocketPacket;
import com.heo.coder.packet.StartPacketRsp;
import com.heo.coder.packet.base.BasePacket;
import com.heo.util.ByteHelper;
import com.heo.util.DeviceCommand;
import com.heo.util.NettyChannelMapUtils;
import com.heo.util.Utils;
import com.heo.pojo.LoginInfoEntity;
import com.heo.pojo.DeviceInfoEntity;
import com.heo.pojo.DeviceModelEntity;
import com.heo.pojo.StateInfoEntity;
import com.heo.pojo.StatusDictEntity;
import com.heo.pojo.OrgInfoEntity;
import com.heo.pub.ApplicationContextUtil;
import com.heo.pub.DictEnum;
import com.heo.service.DeviceInfoService;
import com.heo.service.DeviceModelService;
import com.heo.service.OrgInfoService;
import com.heo.service.StatusDictService;

import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class NettyServerSocketHandler extends ChannelInboundHandlerAdapter {
	private Logger log = Logger.getLogger(this.getClass());
	private short sendSequenceId = 1;
	private String logHeader = "NettyServerSocketHandler";
	private String deviceImei = null;
	public ChannelHandlerContext mCtx;
	private BasePacket basePacket = null;
	private String appId = "";
	private String callUrl = "";
	// 初始化设备，并入库
//    DeviceInfoService deviceInfoService = null;
//    DeviceModelService deviceModelService = null;
    DeviceInfoEntity deviceInfo = null;
    private Map<String, StatusDictEntity> statusDictMap;

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		log.error(logHeader + "[断开]操作异常，socket连接已断开。");
		log.error(cause.getMessage(), cause);
		// 网络异常，断开。
		ctx.close();
	}

	/**
	 * 客户端连接上来的时候触发 连接上来的时候，并不知道客户端是谁，需要根据他后面发的指令才知道是谁。
	 */
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		this.mCtx = ctx;
		String channelId = ctx.channel().id().asShortText();
		String remoteIpAddress = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress().getHostAddress();
		logHeader = "[server][" + channelId + "][" + remoteIpAddress + "]";
		log.info(logHeader + "[连接]与客户端建立连接成功。");
		InitPacketRsp initPacketRsp = new InitPacketRsp();
		initPacketRsp.setPass(BasePacket.PASS);
		sendMessage(initPacketRsp);
	}

	/**
	 * 连接关闭成功后触发
	 */
	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		String channelId = ctx.channel().id().asShortText();
		log.info(logHeader + "[断开]socket连接已断开。" + channelId);
	}

	/**
	 * 收到客户端传上来的数据触发
	 */
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		basePacket = (SocketPacket) msg;
		switch (basePacket.getControl()) {
		case DeviceCommand.LOGIN_COMMAND_REQ:
			// 初始化设备，并入库
			DeviceInfoService deviceInfoService = (DeviceInfoService) ApplicationContextUtil.getBeanById("deviceInfoService");
			DeviceModelService deviceModelService = (DeviceModelService) ApplicationContextUtil.getBeanById("deviceModelService");
		    StatusDictService statusDictService = (StatusDictService) ApplicationContextUtil
					.getBeanById("statusDictService");
		    LoginInfoEntity infoEntity = new LoginInfoEntity(basePacket.getBody());
		    deviceImei = infoEntity.getImei();
		    deviceInfo = deviceInfoService.getDeviceInfoMapByImei(deviceImei);
		    if(deviceInfo == null) {
		    	throw new Exception(deviceImei + "设备不存在请联系管理员!!");
		    }
		    deviceInfoService.initDeviceInfo(infoEntity);
		    OrgInfoService orgInfoService  = (OrgInfoService) ApplicationContextUtil.getBeanById("orgInfoService");
		    OrgInfoEntity orgInfoEntity = orgInfoService.getByKey(deviceImei);
		    appId = orgInfoEntity.getAppId();
		    callUrl = orgInfoEntity.getCallUrl();
		    DeviceModelEntity deviceModel = deviceModelService.getDeviceModelMap(deviceInfo.getDeviceModelId());
		    statusDictMap = statusDictService.getStatusDictMap(deviceModel.getDeviceModelId());
			log.info("--imei--" +  deviceImei +"---- " + "登陆开始   控制码 = " + basePacket.getControl() + basePacket.toString());
			// 初始化设备，并入库
		    NettyChannelMapUtils.add(appId, deviceImei, deviceInfo.getDeviceChannelNum(), Utils.getShort(deviceModel.getDeviceModel()), this);
			CommPacketRsp loginRsp = new CommPacketRsp();
			loginRsp.setMsgContent(deviceInfo, DeviceCommand.LOGIN_COMMAND_REQ);
			sendPacket(ctx.channel(), loginRsp);
			break;
		case DeviceCommand.STATUS_COMMAND_REQ:
			if(!Utils.checkNull(deviceImei) || NettyChannelMapUtils.get(appId, deviceImei) == null) {
				close();
			}
			log.info("--imei--" +  deviceImei +"---- " + "终端心跳  心跳码= " + basePacket.getControl() + "---" + basePacket.toString());
			StateInfoEntity stateInfo = new StateInfoEntity(basePacket.getBody());
			if(stateInfo.getSignal() > 0) {
				NettyChannelMapUtils.updateDeviceSignal(appId, deviceImei, stateInfo.getSignal(), mCtx);
			}
			NettyChannelMapUtils.callBackSendStatus(appId, deviceImei, 0, DictEnum.CallBackType.STATUS_REPORT, stateInfo.getState(), callUrl, statusDictMap, ctx);
			CommPacketRsp commRsp = new CommPacketRsp();
			commRsp.setMsgContent(deviceInfo, DeviceCommand.STATUS_COMMAND_REQ);
			sendPacket(ctx.channel(), commRsp);
			break;
		default:
			CommPacketRsp commRsps = new CommPacketRsp();
			commRsps.setMsgContent(deviceInfo, basePacket.getControl());
			sendPacket(ctx.channel(), commRsps);
			break;
		}
	}

	/**
	 * 发送数据包 当没办法提交给队列时使用
	 * 
	 * @param ctx
	 * @param packet
	 */
	public synchronized void sendPacket(Channel channel, BasePacket packet) {
		channel.writeAndFlush(packet).addListener(new ChannelFutureListener() {
			// 数据发送完毕后，触发本事件
			@Override
			public void operationComplete(ChannelFuture future) throws Exception {
				log.debug(logHeader + deviceImei + "[应答]向设备<" + packet.getControl()
				+ ">发送数据成功， 发送内容：" + packet.toString());
			}
		});
	}
	
	/**
	 * 发送消息
	 * 
	 * @param rspJsonMap
	 * @throws Exception
	 */
	public synchronized void sendMessage(BasePacket packet)
			throws Exception {
		if (packet != null && mCtx != null) {
			mCtx.writeAndFlush(packet).addListener(new ChannelFutureListener() {
				// 数据发送完毕后，触发本事件
				@Override
				public void operationComplete(ChannelFuture future) throws Exception {
					log.debug(logHeader + deviceImei + "[应答]向设备<" + packet.getControl()
							+ ">发送数据成功， 发送内容：" + packet.toString());
				}
			});
		}
	}
	
	public synchronized void startWorking(String cmd) throws Exception {
		log.info("startCharging" + deviceImei + "向设备<" + basePacket.getControl() + ">发送数据成功， 发送开始");
		StartPacketRsp startRsp = new StartPacketRsp();
		startRsp.setMsgContent(cmd);
		if(mCtx != null) {
			sendPacket(mCtx.channel(), startRsp);
		}
	}
	
	public synchronized void setIpPort(String ip, String port) throws Exception {
		log.info("endCharging" + deviceImei + "向设备<" + basePacket.getControl() + ">发送数据成功， 发送结束");
		SetIpPortPacketRsp setIpPortPacketRsp = new SetIpPortPacketRsp();
//		String flowNumberStr = flowNumber.get(deviceImei + passageway);
//		if(!Utils.checkNull(flowNumberStr)) {
//			flowNumberStr = "00000000";
//		}
//		endPacketRsp.setMsgContent(passageway, flowNumberStr, "13000000000");
		setIpPortPacketRsp.setMsgContent(ip, Integer.parseInt(port));
		sendMessage(setIpPortPacketRsp);
	}
	
	public void close() throws IOException {
		if (mCtx != null) {
			NettyChannelMapUtils.remove(appId, deviceImei);
			mCtx.close();
		}
	}
	
	private String getSendSequenceIdHex() {
		if(sendSequenceId == 65535) {
			sendSequenceId = 1;
		}
		sendSequenceId++;
		return ByteHelper.shortToHexString(sendSequenceId);
	}
}
